/*
 * MusicLabs, Copyright (C) 2008-2009 Felippe Ragghianti <felipperag@gmail.com>
 *                                    Savio Sena <savio.sena@gmail.com>
 *                                    http://code.google.com/p/musiclabs
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */


package br.com.music.player;

import br.com.music.rhythm.Beat;
import br.com.music.rhythm.TimeSignature;
import java.util.Vector;

/**
 * The Metronome is meant to mark Time Signature beats during the exibition
 * of a peace. It's used as parameter to practice playing most of the time,
 * but could be used for other purposes as well.
 *
 * There are two types of metronome: SIMPLE and RHYTHMIC.
 * @see MetronomeType
 */
// XXX : Metronome could extend Instrument instead.
public class Metronome implements Playable {

    /**
     * The Metronome can be of two types:
     *
     * The SIMPLE Metronome plays only the strong marks, i.e., one beat per
     * time signature, or per "compasso" (pt).
     *
     * The RHYTHMIC Metronome plays beats of all types generating a full
     * and richer "compasso". A single 4/N time signature, for exemple would,
     * generate an output of Beat.STRONG, Beat.WEAK, Beat.MEDIUM, Beat.WEK.
     *
     * Both types are usefull, and it's a matter of taste mainly which type
     * to choose.
     */
    public enum MetronomeType {
       SIMPLE,
       RHYTHMIC
    }

    /** Time signature. */
    TimeSignature timeSig;

    /** Metronome type. */
    MetronomeType type;

    /**
     * Default class constructor.
     * 
     * When no parameters are specified the class creates a Metronome
     * of type MetronomeType.SIMPLE with time signature 4/2.
     *
     * This constructor doesn't really throw exceptions -- well, that's
     * interesting; the reason is because TimeSignature constructor only
     * throws exception for invalid arguments, and TimeSignature.QUADRUPLE
     * is always valid.
     */
    public Metronome() throws Exception {
        this(new TimeSignature(TimeSignature.QUADRUPLE));
    }

    /**
     * This constructors creates a MetronomeType.SIMPLE Metronome object
     * relying on the TimeSignature passed as argument.
     * 
     * @param timeSig Time Signature.
     */
    public Metronome(TimeSignature timeSig) {
        this(MetronomeType.SIMPLE, timeSig);
    }

    /**
     * This constructor instantiates a Metronome given a MetronomeType.
     *
     * @param type Metronome type.
     */
    public Metronome(MetronomeType type) {
        super();
        this.type = type;
    }

    /**
     * Default constructor.
     *
     * @param type Metronome type.
     * @param timeSig Time signature.
     */
    public Metronome(MetronomeType type, TimeSignature timeSig) {
        this.type = type;
        this.timeSig = timeSig;
    }

    /**
     * Set metronome's time signature.
     *
     * @param timeSig Time signature.
     */
    public void setTimeSignature(TimeSignature timeSig) {
        this.timeSig = timeSig;
    }

    /**
     * Get metronome's current time signature.
     *
     * @return This method returns metronome's current time signature. Please
     * notice that, since it's possible to set metronome's type anytime,
     * this method is not thread-safe.
     */
    public TimeSignature getTimeSignature() {
        return this.timeSig;
    }

    /**
     * *PRIVATE* Get metronome's type.
     *
     * This method is meant to be *PRIVATE*. No one should ever change the
     * metronome's type; nor any methods inside this class should ever invoke 
     * it. Just for the sake of semantics.
     *
     */
    private MetronomeType setType() {
        throw new UnsupportedOperationException("This method should not " +
                "be invoked.");
    }
    
    /**
     * Get metronome's type.
     *
     */
    public MetronomeType getType() {
       return this.type;
    }

    /**
     * Generates playable text.
     *
     * @return Playable text as String.
     */
    @Override
    public String toString() {
        String timeSignature = "";
        Vector<Beat> beats = this.timeSig.getBeats();
        for(Beat beat : beats) {
            if(this.type == MetronomeType.RHYTHMIC ||
                (this.type == MetronomeType.SIMPLE &&
                   beat.getStrength() == Beat.STRONG))
            {
                timeSignature += beat;
            }
        }
        return timeSignature;
    }       
}

